package com.hb.B_面向对象.E_密封类_代数类型

import io.reactivex.rxkotlin.toMaybe
import reactor.core.publisher.Mono
import reactor.core.publisher.toMono
import com.hb.B_面向对象.E_密封类_代数类型.mapToMono as mapToMono

/**
 *
public abstract class Either<E, V> {
private Either() {}
}

public final class Left<E> extends Either {
private final E left;
}

public final class Right<V> extends Either {
private final V right;
}
 */
sealed class Either<out E, out V>
data class Left<out E>(val left: E) : Either<E, Nothing>()
data class Right<out V>(val right: V) : Either<Nothing, V>()


fun <E, V> Either<E, V>?.getRightValueOrNull(): V? {
    return when (this) {
        is Right -> this.right
        else -> null
    }
}

fun <T, E, V> Either<E, V>.map(fn: (value: V) -> T): Either<E, T> {
    return when (this) {
        is Left -> this
        // this.right,如果是right,就去执行函数
        is Right -> Right(fn(this.right))
    }
}

/**
 * 解释这个函数的作用：如果是Left类型，直接返回那个对象。如果是Right类型，就去调用fn的函数,fn这个函数返回值又是：Either<E, T>
 */
fun <T, E, V> Either<E, V>.flatMap(fn: (value: V) -> Either<E, T>) =
    when (this) {
        is Left -> this
        is Right -> fn(this.right)
    }

/**
 * 这个函数的作用就是：
 *  如果是Left类型，就toMono，
 *  如果是Right类型，就去执行fn这个函数，fn的返回值就是Mono<T>
 */
fun <T, E, V> Either<E, V>.mapToMono(fn: (value: V) -> Mono<T>): Mono<Either<E, T>> {
    return when (this) {
        is Left -> this.toMono()
        is Right -> fn(this.right).map { Right(it) }
    }
}



fun <T, E, V> Either<E, V>.flatMapToMono(fn: (value: V) -> Mono<Either<E, T>>): Mono<Either<E, T>> =
    when (this) {
        //转为Mono
        is Left -> this.toMono()
        // fn: (value: V) -> Mono<Either<E, T>> 返回值就是Mono，所以这个flatMapToMono方法可以将数据转为Mono
        is Right -> fn(this.right)
    }

fun <T, E, V> Mono<Either<E, V>>.mapEither(fn: (value: V) -> T): Mono<Either<E, T>> {
    return this.map {
        it.map(fn)
    }
}

//sealed class Either<out E, out V>{
//    data class Left<out E>(val left: E) : Either<E, Nothing>()
//    data class Right<out V>(val right: V) : Either<Nothing, V>()
//}
//fun <E, V> Either<E, V>?.getRightValueOrNull(): V? {
//    return when (this) {
//        is Either.Right -> this.right
//        else -> null
//    }
//}
//
//
//fun main() {
//    var either=Either.Left(1)
//    var rightValueOrNull = either.getRightValueOrNull()
//    println("rightValueOrNull: $rightValueOrNull")
//}

fun main() {
    var left = Left(1)
    var rightValueOrNull = left.getRightValueOrNull()
    println("rightValueOrNull: $rightValueOrNull")


    var mapLeft = left.map {
        it
    }
    println("mapLeft= $mapLeft")

    var right = Right(1)

    //fun <T, E, V> Either<E, V>.map(fn: (value: V) -> T): Either<E, T>
    var mapRight = right.map {
        //fn: (value: V) -> T 下面这个函数的作用就是让参数*2，然后返回，理解的意思就是：输入一个参数，然后执行函数体 it*2 ,然后返回这个值
        it * 2
    }
    println("mapRight=$mapRight")

    //fun <T, E, V> Either<E, V>.flatMap(fn: (value: V) -> Either<E, T>)
    var flatMapRight=right.flatMap {
        right
        //传进去的函数表示：传进一个参数，返回一个Right
//        it -> right
    }
    println("flatMapRight =$flatMapRight")

    var flatMapLeft= left.flatMap {
        right
    }
    println("flatMapLeft =$flatMapLeft")

    var mapToMonoLeft= left.mapToMono {
        right.toMono()
    }
    println("mapToMonoLeft =$mapToMonoLeft")


    var mapToMonoRight= right.mapToMono {
        left.toMono()
    }

    println("mapToMonoRight =$mapToMonoRight")




}